package myApp;

public class Hanoi {
    public static void main(String[]args){
        int n=0;                                        //Кол-во дисков
        try{
            n=Integer.parseInt(args[0]);
            if(n<=0) throw new RuntimeException("negative argument");
            if(n>10) throw new RuntimeException("argument must be 0<arg<10");
        }catch (Exception e){
            System.err.println("WRONG ARGUMENT PARAMETER, ARGUMENT MUST BE INTEGER"+e);
            System.exit(1);
        }
        Hanoi hanoi=new Hanoi();
        hanoi.run(n);
    }

    private void run(int n){
        int countDisk, counter = 1, count;

        while (counter <= Math.pow(2, n) - 1) { /* Запускаем цикл повторений */

            if (counter % 2 != 0) { /* На нечетном ходу мы будем трогать только самый маленький диск */
                System.out.print(counter +" "+ 1+" ");
                hanoi(n, counter, 1); /* С помощью этой функции определяем для данного диска перемещение */
            }

            else {  /* Определяем диск который нужно переместить на четном ходу */
                count = counter;
                countDisk = 0;

                while (count % 2 == 0) {  /* Диск который нужно переместить */
                    countDisk++;           /* будет числом деления номера хода на 2 без остатка */
                    count = count / 2;
                }
                System.out.print(counter+" "+(countDisk+1)+" ");
                hanoi(n, counter, countDisk + 1);
            }
            counter++;
        }
        System.out.println("(Step#)(Disc#)(StickFrom#)->(StickTo#)");
    }

    private void hanoi(int n,int i,int k){
        int t, axisX, axisY, axisZ;

        if (n % 2 == 0) {  /* Определяем порядок осей в зависимости от четности */
            axisX = 1;      /* и не четности количества дисков */
            axisY = 2;
            axisZ = 3;
        }

        else {
            axisX = 1;
            axisY = 3;
            axisZ = 2;
        }

   /* Номер хода можно представить единственным образом */
   /* как произведение некоего нечетного числа на степень двойки */
   /* k будет номером диска который мы перемещаем */
        t = (int) (((i / Math.pow(2, k - 1)) - 1) / 2);

        if (k % 2 != 0) {    /* Определяем перемещение дисков  для нечетного хода */

            switch (t % 3) {         /* Выбираем перемещение в зависимости от данного условия */
                case 0:
                    System.out.println(axisX+" -> "+axisY);
                    break;
                case 1:
                    System.out.println(axisY+" -> "+axisZ);
                    break;
                case 2:
                    System.out.println(axisZ+" -> "+axisX);
                    break;
                default: throw new RuntimeException();
            }
        }

        else {     /* Определяем перемещение дисков  для чётного хода */

            switch (t % 3) {
                case 0:
                    System.out.println(axisX+" -> "+axisZ);
                    break;
                case 1:
                    System.out.println(axisZ+" -> "+axisY);
                    break;
                case 2:
                    System.out.println(axisY+" -> "+axisX);
                    break;
                default: throw new RuntimeException();
            }
        }
    }
}

